var runtimeChampsBattle = null;
var Code = null;
var Camp = null;
var City = null;
var Action = null;

//战斗记录条数
var FIGHT_RECORD_NUM = 7;
//战场消息记录条数
var FIELD_MESSAGE_NUM = 5;
//玩家战报记录条数
var PLAYER_RECORD_NUM = 10;
//部队血量基数
var ARMY_HEALTH_BASE = 10000;

exports._initRuntime = function() {
    runtimeChampsBattle = gConfRuntime.champsbattle;
    Code = runtimeChampsBattle.Code;
    Camp = runtimeChampsBattle.Camp;
    City = runtimeChampsBattle.City;
    Action = runtimeChampsBattle.Action;
}

function compareServerHistory(a, b) {
	if (a.score != b.score) {
		return b.score - a.score;
	} else {
		return b.sid - a.sid;
	}
}


function ChampsBattle() {
    //需要保存的数据
    this.data = {};

    //当前tick
    this.nowTick = 0;
    //当前时间
    this.nowTime = Date.getStamp();
    //当前周期
    this.nowRound = runtimeChampsBattle.getRound();
    //当前周期中的秒数
    this.nowRoundSeconds = runtimeChampsBattle.getRoundSeconds();
    //当前阶段在周期中的开始时间
	this.stepStartRoundSeconds = 0;

    this.reset();

    //玩家缓存数据,已注册的区服的玩家都会缓存在此
    this.cacheUsers = {
        /*
        $uid: {
            sid: 0,                 //服务器id
            teams: {				//部队缓存信息
            	$id: {
            		city: 0,			//城池
            		sn: 0,				//序号
                    army: {},           //army对象的引用
            	}
            }
            records:[]              //战报缓存信息
        }
        */
    };

    //战场缓存数据,未开始的战场也会缓存在此
    this.cacheFields = {
        /*
        $fieldId: 0,            //战场NPC部队开放天数
        $fieldId: {
            npcDay:0,             //战场NPC部队开放天数
            messages:{stamp,name,sid,id,city},          //最近一条召唤消息{时间戳, 召唤玩家名字, 召唤服务器, NpcId, NPC到达城池}
            topUsers:{$uid:{sid,name,score,rank}},      //排行榜信息
            citys:{$cityId:{records:[]}}                //每个城池的信息
        }
        */
    };
    
    //部队序号标识
    this.armySN = 0;

    this.dirty = {};
}

ChampsBattle._id = 'champsbattle';
ChampsBattle.create = function() {
    var tempChampsBattle = new ChampsBattle();
    gDBWorld.insert(tempChampsBattle.data, function(err, result){});
}

ChampsBattle.prototype = {

    reset: function() {
        this.data = {
            _id: ChampsBattle._id,

            round: this.nowRound,
            schedule: {
                step: runtimeChampsBattle.StepWaiting,
                keep: false,
            },

            registers: {      //注册玩家信息
                /*
                $sid: {$uid:擂台排名}
                */
            },

            servers: {        //各区服数据
                /*
                $sid: {
                    sid: 0,
                    fieldId: 0,         //战场,在每阶段结束时分配下一阶段所属战场
                    camp: 0,            //阵营,在每阶段结束时分配下一阶段所属阵营或重置为中立
                    fight_force: 0,     //总战力
                    worth : 0,          //身价
                    startTime: 0,       //开服时间
                }
                */
            },

            fieldHistorys: {        //各战场历史数据,所有战场都将提前初始化,各战场区服在相应阶段分配
                /*
                $fieldId: {
                    $sid: {
                        camp: 0,            //阵营
                        socre: 0,           //积分
                        npcScore: 0,        //NPC获得的积分
                        win: 0,             //胜利标志(0/1 负/胜)
                    }
                }
                */
            },

            fields: {             //正在进行的战场数据
                /*
                $fieldId: {
                    $cityId: {
                    	id:0,
                        camp: 0,            //所属阵营
                        level: 0,           //城池等级
                        resource: 0,		//资源数量

                        armys: {            //各阵营的部队
                            $camp: {			//阵营
                            	$sn: {				//序号,用于排序
                                	uid:0,              //玩家Id,为0表示召唤的NPC 
                                	id:0,               //阵型编号(前军/中军/后军),为NPC时表示怪物编号
                                    kill:0,             //连斩数
                                    health:0            //NPC专用,血量比例
                                    name:'',            //玩家专用,玩家名称
                                    score:0             //玩家专用,获得积分
                                    resource:0          //玩家专用,拥有资源
                                    dead:0              //玩家专用,是否阵亡
                                    status: {           //状态,无状态时为null
                                        action: 0,          //任务行为名称
                                        start: 0,           //开始时间
                                        timeout: 0,         //任务时长
                                        param: 0,           //参数,对于战斗表示剩余血量，对于移动表示目标城池
                                    },
                                }			
                            }
                        },

                        records: [{         //战斗记录,保存最近
                            stamp:0,            //时间
                            success:0,          //是否胜利
                            atk:{name,uid,id,fight,kill},  //进攻方名称,uid,阵型id,战斗力,战前连斩数
                            def:{name,uid,id,fight,kill},  //防御方
                            win:{kill,score,health} //胜利方连斩数,获得积分,剩余血量百分比
                        }]
                    }
                }
                */
            },

            serverTopUsers: {},
        }
        
        var data = this.data;
        objectForEachKey(gConfChampsBattleField, function(fieldId) {
            data.fieldHistorys[fieldId] = {};
        });
    },

    init: function(callback) {
        gDBWorld.findOne({_id : ChampsBattle._id}, {}, function(err, doc) {
            if (err || !doc) {
                callback && callback(err || 'doc null');
                return;
            }

            this.data = doc;
            this._init();
            callback && callback();
        }.bind(this));
    },

    _init: function() {
    	this._updateStepStartRoundSeconds();
        this._rebuildCacheUsers();

        var armySN = this.armySN;
        var cacheUsers = this.cacheUsers;
        var fields = this.data.fields;
        for (var fieldId in fields) {
            var fieldCitys = fields[fieldId];
            for (var cityId in fieldCitys) {
                cityId = +cityId;
                var cityArmys = fieldCitys[cityId].armys;
                for (var camp in cityArmys) {
                	var armys = cityArmys[camp];
                	objectForEach(armys, function(sn, army) {
                        sn = +sn;
                		armySN = Math.max(armySN, sn);
                    	if (army.uid) {
                            var userCache = cacheUsers[army.uid];
                            if (userCache) {
                                userCache.teams[army.id] = {city:cityId, sn:sn, army:army};
                            }
                        }
                	});
                };
            }
        }
        this.armySN = armySN;

        this._rebuildFieldCaches();
    },

    //标记有变化的数据
    markDirty: function(item) {
        this.dirty[item] = 0;
    },
    
    //保存的变化的数据
    save: function(force, callback) {
        if (Object.keys(this.dirty).length < 1) {
            callback && callback(); return;
        }

        var sets = {};
        var dirty = this.dirty;
        var data = this.data;
        objectForEachKey(dirty, function(item) {
            sets[item] = data[item];
        });
        this.dirty = {};

        gDBWorld.update({_id : this.data._id}, {'$set':sets}, function(err, result) {
            if (err) {
                ERROR(util.format('champsbattle save error:%j, sets:%j', err, sets));
            }
            callback && callback(err);
        });
    },

    //保存所有数据
    saveAll: function(callback) {
        this.dirty = {};
        var data = this.data;
        gDBWorld.save(this.data, function(err, result) {
            callback && callback(err);
        });
    },
    
    newArmySN: function() {
    	return ++this.armySN;
    },



    //更新前阶段在周期中的开始时间
    _updateStepStartRoundSeconds: function() {
    	var nowStep = this.data.schedule.step;
    	var stepConf = gConfChampsBattleSchedule[nowStep];
    	if (stepConf) {
    		this.stepStartRoundSeconds = stepConf.StartSeconds;
    	}
    },

    //重构玩家缓存信息
    _rebuildCacheUsers: function() {
        var registers = this.data.registers;
        this.cacheUsers = {};
        for (var sid in registers) {
            this._buildServerCacheUsers(+sid);
        }
    },
    
    //构建某区服的玩家缓存信息
    _buildServerCacheUsers: function(sid) {
        var serverRegisters = this.data.registers[sid];
        if (!serverRegisters) {
            return;
        }
        
        var cacheUsers = this.cacheUsers;
        objectForEachKey(serverRegisters, function(uid) {
            cacheUsers[uid] = {
                sid: sid, 
                teams: {}, 
                records: new LimitedVector(PLAYER_RECORD_NUM),
            }
        });
    },
    
    //重构战场缓存信息
    _rebuildFieldCaches: function() {
        var fieldHistorys = this.data.fieldHistorys;
        var servers = this.data.servers;
        var cacheFields = this.cacheFields;
        var nowTime = this.nowTime;


        objectForEach(fieldHistorys, function(fieldId, fieldHistory) {
            //计算战场服务器平均开服天数
            var serverNum = 0;
            var totalStartTime = 0;
            for (var sid in fieldHistory) {
                var server = servers[sid];
                serverNum++;
                totalStartTime += server.startTime;
            }

            var startTime = (serverNum > 1) ? Math.floor(totalStartTime/serverNum) : totalStartTime;
            var openDays = Math.floor((nowTime - startTime)/86400);

            //计算NPC的天数
            var matchDay = 1;
            var teamIndexs = runtimeChampsBattle.teamIndexs;
            objectForEachKey(teamIndexs, function(day) {
                var npcDay = +day;
                if (openDays >= npcDay && npcDay > matchDay) {
                    matchDay = npcDay;
                }
            });
            
            //创建战场缓存信息
            var cacheField = {
                'npcDay': matchDay,
                'messages': new LimitedVector(FIELD_MESSAGE_NUM),
                'topUsers': {},
                'citys':{},
            };
            
            cacheFields[fieldId] = cacheField;
            objectForEachKey(gConfChampsBattleFieldCity, function(cityId) {
                cacheField.citys[cityId] = {records:new LimitedVector(FIGHT_RECORD_NUM)}
            });
        });
    },




    //每帧处理逻辑
    tick: function() {
        this.nowTick++;
    	this.nowTime = Date.getStamp();
        this.nowRound = runtimeChampsBattle.getRound();
        this.nowRoundSeconds = runtimeChampsBattle.getRoundSeconds();

        if (this.data.round != this.nowRound) {
            ERROR(util.format('champsbattle nowRound=%d round=%d schedule=%j', this.nowRound, this.data.round, this.data.schedule));
            this.reset();
            this.saveAll();
            this._updateStepStartRoundSeconds();
            this._rebuildCacheUsers();
            this._rebuildFieldCaches();
            return;
        }

        var nowSchedule = runtimeChampsBattle.getSchedule();
        while (this.data.schedule.step != nowSchedule.step || this.data.schedule.keep != nowSchedule.keep) {
            ERROR(util.format('champsbattle schedule=%j nowSchedule=%j', this.data.schedule, nowSchedule));
            this.data.schedule = runtimeChampsBattle.getNextSchedule(this.data.schedule);
            this.markDirty('schedule');
            this._doSchedule();
        }
        
        if (this.isFightingSchedule()) {
            this._doUpdateFieldStatus();

        	if (1 == (this.nowTick % gConfGlobal.ChampsBattleBattleNeedTime)) {
        		this._doUpdateFieldFight();
        	}
        	
        	if (59 == (this.nowTick % 60)) {
        		this._doUpdateFields();
                this._doUpdateFieldRanks();
        	}
        }
    },

    //处理每阶段逻辑
    _doSchedule: function() {
    	this._updateStepStartRoundSeconds();
    	
        var schedule = this.getSchedule();
        var stepConf = gConfChampsBattleSchedule[schedule.step];
        if (!stepConf) {
        	return;
        }
        
        //调用阶段处理函数 
        var handlerName = null;
        if (runtimeChampsBattle.StepRegister == schedule.step) {
            handlerName = util.format('_doStepRegister%s', schedule.keep ? 'Begin' : 'End');
        } else {
            handlerName = util.format('_doGroup%d%s', stepConf.Group, schedule.keep ? 'Begin' : 'End');
        }

        var scheduleHandler = this[handlerName];
        if (scheduleHandler) {
            ERROR('champsbattle ' + handlerName);
            scheduleHandler.apply(this);
        }
    },

    //注册阶段开始
    _doStepRegisterBegin: function() {
    },
    
    //注册阶段结束
    _doStepRegisterEnd: function() {
        //各服务器按战斗力排行
        var rankServers = [];
        objectForEach(this.data.servers, function(sid, server) {
            rankServers.push(server);
        });
        rankServers.sort(function(a, b){
            return b.fight_force - a.fight_force; 
        });

        //根据区服战斗力为下一阶段分组
        var schedule = this.getSchedule();
        var rank = 0;
        var maxRank = rankServers.length;
        var fieldIdArray = runtimeChampsBattle.stepFields[schedule.step + 1];
        var fieldHistorys = this.data.fieldHistorys;
        fieldIdArray.forEach(function (fieldId) {            
            var fieldHistory = {};
            [Camp.kShu, Camp.kWei].forEach(function(camp) {
                rank++;
                if (rank > maxRank) {
                    return true;
                }

                var server = rankServers[rank - 1];
                server.fieldId = fieldId;
                server.camp = camp;
                fieldHistory[server.sid] = {camp: camp, score: 0, win:0, npcScore:0};
            });
            fieldHistorys[fieldId] = fieldHistory;
        });

        this.markDirty('fieldHistorys');
        this._prepareFields(fieldIdArray);
    },

    //4强赛开始
    _doGroup4Begin: function() {
    },

    //4强赛结束
    _doGroup4End: function() {
    	this._endFields();
    	this._groupNextFields();
    },

    //2强赛开始
    _doGroup2Begin: function() {
    },

    //2强赛结束
    _doGroup2End: function() {
    	this._endFields();
    	this._groupNextFields();
    },

    //总决赛开始
    _doGroup1Begin: function() {
    },

    //总决赛结束
    _doGroup1End: function() {
    	this._endFields();
    },
   

    //结束战场
    _endFields: function() {
    	//统计各区服总积分和各玩家积分
        var serverResults = {}; //sid:{score:0, ranks:[]}
    	var cacheUsers = this.cacheUsers;
        objectForEach(cacheUsers, function(uid, userCache) {
            var score = 0;
            objectForEach(userCache.teams, function(id, team) {
                score += team.army.score;
            });

            if (score > 0) {
                var sid = userCache.sid;
                serverResult = serverResults[sid];
                if (!serverResult) {
                    serverResult = {score:0, ranks:[]};
                    serverResults[sid] = serverResult;
                }
                serverResult.score += score;
                serverResult.ranks.push({uid:uid, score:score});
            }
        });

        
        //重置数据
    	var servers = this.data.servers;
        objectForEach(servers, function(sid, server) {
            server.camp = Camp.kMid;
        });

        objectForEach(cacheUsers, function(uid, userCache) {
            userCache.teams = {};
        });

    	this.data.fields = {};
        this.data.serverTopUsers = {};
        
        //存积分到战场历史数据并计算胜负
        //重新生成服务器积分排行榜
    	var schedule = this.data.schedule;
    	var fieldHistorys = this.data.fieldHistorys;
        var serverTopUsers = this.data.serverTopUsers;
    	var fieldIdArray = runtimeChampsBattle.stepFields[schedule.step];

    	fieldIdArray.forEach(function(fieldId) {
    		var fieldHistory = fieldHistorys[fieldId];
            var fieldServers = [];

    		for (var sid in fieldHistory) {
                var serverResult = serverResults[sid] || {score:0, ranks:[]};
                serverResult.ranks.sort(function(a, b) {
                    return b.score - a.score;
                });
                
                var serverHistory = fieldHistory[sid];
                serverHistory.score = serverHistory.npcScore + serverResult.score;
                fieldServers.push({sid:sid, score:serverHistory.score});

                var resultRanks = serverResult.ranks; 
                var topUsers = {};
                for (var i = 0, len = resultRanks.length; i < len; ++i) {
                    var rankUser = resultRanks[i];
                    var player = gPlayers.get(rankUser.uid);
                    if (player) {
                        player.getChampsBattle().score = rankUser.score;
                        player.markDirty('champsbattle.score');
                        if (i < 1) {
                            topUsers[rankUser.uid] = {sid:sid, name:player.user.info.un, score:rankUser.score, rank:i+1};
                        }
                    }
                }
                serverTopUsers[sid] = topUsers;
            }

            if (fieldServers.length > 0) {
                fieldServers.sort(compareServerHistory);
                var winServer = fieldServers[0];
                fieldHistory[winServer.sid].win = 1;
            }
        });

        //保存数据
        this.markDirty('fields');
    	this.markDirty('servers');
    	this.markDirty('fieldHistorys');
    	this.markDirty('serverTopUsers');
    },
    
    //分组下一轮战场
    _groupNextFields: function() {
    	var schedule = this.data.schedule;
    	var curFieldArray = runtimeChampsBattle.stepFields[schedule.step];
    	var nextFieldArray = runtimeChampsBattle.stepFields[schedule.step + 1];
    	if (!curFieldArray || !nextFieldArray) {
    		return;
    	}
    	
    	//计算获胜的服务器列表
    	var winServers = []; //{sid, score}
    	var fieldHistorys = this.data.fieldHistorys;    	
    	curFieldArray.forEach(function(fieldId) {
     		var fieldHistory = fieldHistorys[fieldId];
    		for (var sid in fieldHistory) {
                var fieldServer = fieldHistory[sid];
                if (fieldServer.win) {
                    winServers.push({sid:sid, score:fieldServer.score});
                    break;
                }
    		}
    	});
    	winServers.sort(compareServerHistory);
    	
    	//将获胜服务器分配到下一轮战场中
    	var rank = 0;
    	var maxRank = winServers.length;
    	var servers = this.data.servers;
        nextFieldArray.forEach(function (fieldId) {
            var fieldHistory = {};
            [Camp.kShu, Camp.kWei].forEach(function(camp) {
                rank++;
                if (rank > maxRank) {
                    return true;
                }
                
                var sid = winServers[rank - 1].sid;
				var server = servers[sid];
                server.fieldId = fieldId;
                server.camp = camp;
                fieldHistory[sid] = {camp:camp, score:0, npcScore:0, win:0};
            });
            fieldHistorys[fieldId] = fieldHistory;
        });
        
        this.markDirty('servers');
        this.markDirty('fieldHistorys');
        this._prepareFields(nextFieldArray);
    },

    //更新战场部队状态
    _doUpdateFieldStatus: function() {
        var nowTime = this.nowTime;
    	var fields = this.data.fields;
        var me = this;

    	for (var fieldId in fields) {
    		var field = fields[fieldId];

    		for (var cityId in field) {
    			var city = field[cityId];
                var campArmys = city.armys;

                for (var camp in campArmys) {
                    var armys = campArmys[camp];

                    objectForEach(armys, function(sn, army) {
                        var army = armys[sn];
                        var status = army.status;
                       
                        //判断事件状态是完成
                        if (!status || (nowTime < (status.start + status.timeout - 2))) {
                            return;
                        }
                        delete army.status;

                        //处理已完成的定时事件
                        switch (status.action) {
                        case Action.kMove:
                            var destCityId = status.param;
                            me.addArmyToFieldCity(fieldId, destCityId, camp, army);
                            delete armys[sn];
                            break;
                        case Action.kBattle:
                            if (status.param) {
                                if (army.uid) {
						            var mainCityId = runtimeChampsBattle.mainCitys[camp];
                                    me.addArmyToFieldCity(fieldId, mainCityId, camp, army);
                                }
                                delete armys[sn];
                            }
                            break;
                        default:
                            break;
                        }
                    });
                }
            }
        }

        this.markDirty('fields');
    },
    
    //更新战场战斗
    _doUpdateFieldFight: function() {
    	var fields = this.data.fields;
        var nowTime = this.nowTime;

    	for (var fieldId in fields) {
    		var field = fields[fieldId];

    		for (var cityId in field) {
    			var city = field[cityId];
    			var cityConf = gConfChampsBattleFieldCity[cityId];
    			
    			if(City.kBattle != cityConf.Type) {
    				continue;
    			}
    			
    			//计算攻击和防御阵营
    			var atkCamp = (Camp.kShu == city.camp) ? Camp.kWei : Camp.kShu;
    			var defCamp = (Camp.kShu == city.camp) ? Camp.kShu : Camp.kWei;
    		
                //找到攻防阵营的部队序号
    			var campArmys = city.armys;	
    			var attackerArmys = campArmys[atkCamp];
    			var defnederArmys = campArmys[defCamp];
    			var atkArmy = this._selectFightArmy(attackerArmys);
    			var defArmy = this._selectFightArmy(defnederArmys);
    			if (!atkArmy || !defArmy) {
    				continue;
    			}

    			//计算城池防御加成
    			var cityLevelConf = gConfChampsBattleCityLevel[city.level];
    			var defAttrRates = null;
    			if (Camp.kMid != cityConf.camp) {
    				defAttrRates = {
    					'defence': +cityLevelConf.DefencePlus,
    					'mdefence': +cityLevelConf.MagicDefencePlus,
    				}
    			}
    		    
                try {
    			    //创建战斗对象
    			    var atkFighter = this._createFighter(atkArmy, cityLevelConf);
    			    var defFighter = this._createFighter(defArmy, cityLevelConf, defAttrRates);
    			    if (!atkFighter || !defFighter) {
    			    	continue;
    			    }

    			    //处理战斗结果
    			    var report = atkFighter.fight(defFighter);
                    var record = {
                        stamp: nowTime, 
                        success: report.success,
                        replay: gReplay.addReplay(report),
                        city: +cityId,
                        atk: {fight:atkFighter.teamFightForce, kill:atkArmy.kill},
                        def: {fight:defFighter.teamFightForce, kill:defArmy.kill},
                        atkFighter: atkFighter,
                        defFighter: defFighter,
                    }
                    
                    var isAtkWin = report.success ? true : false;
                    this._processArmyFightResult(fieldId, atkCamp, atkArmy, atkFighter, record.atk, isAtkWin);
                    this._processArmyFightResult(fieldId, defCamp, defArmy, defFighter, record.def, !isAtkWin);
                    record.win = isAtkWin ? {kill:atkArmy.kill, health:atkArmy.health} : {kill:defArmy.kill, health:defArmy.health};
                    
                    //保存战斗记录
                    this.cacheFields[fieldId].citys[cityId].records.add(record);
                    this._saveArmyFightRecord(atkArmy, record);
                    this._saveArmyFightRecord(defArmy, record);
                } catch (e) {
                    ERROR(util.format('champsbattle fight exception atkArmy=%j defArmy=%j', atkArmy, defArmy));
                    ERROR(e.stack);
                    var defaultBattleStatus = {
                        action: Action.kBattle, 
                        start: nowTime, 
                        timeout: gConfGlobal.ChampsBattleBattleNeedTime, 
                        param: true,
                    };
                    atkArmy.status = defaultBattleStatus;
                    defArmy.status = defaultBattleStatus;
                }
			}
    	}
        this.markDirty('fields');
    },
    
    //从部队列表中选择一支参战
    _selectFightArmy: function(armys) {
        var snArr = Object.keys(armys);
        for (var i = 0, len = snArr.length; i < len; ++i) {
            var sn = snArr[i];
            var army = armys[sn];
            if (!army.status) {
                return army;
            }
        }
    },
    
    //创建战斗对象
    _createFighter: function(army, growthConf, attrRates) {
    	var fighter = null;
    	var attackRate = 0;
    	var defenceRate = 0;
    	var mdefenceRate = 0;
    	if (attrRates) {
    		defenceRate = (attrRates.defence || 0);
    		mdefenceRate = (attrRates.mdefence || 0);
    	}
    	
    	if (army.uid) {
    		var player = gPlayers.get(army.uid);
    		if (!player) {
    			return null;
    		}
    		
    		var champsbattle = player.getChampsBattle();
    		var team = champsbattle.teams[army.id];
    		if (!team || team.dead) {
    			return null;
    		}
    		
    		fighter = new Fighter();
    		fighter.initWithChampsBattle(player, champsbattle, team.team);
    		
    		if (army.kill >= gConfGlobal.ChampsBattleTeamTiredKills) {
    			var rate = Math.min((army.kill - gConfGlobal.ChampsBattleTeamTiredKills + 1), 4) * -20;
    			attackRate += rate;
    			defenceRate += rate;
    			mdefenceRate += rate;
    		}
    	} else {
    		var teamConf = gConfChampsBattleTeam[army.id];
    		if (!teamConf) {
    			return null;
    		}
    		
    		fighter = new Fighter();
    		fighter.initWithChampsBattleMonster(teamConf, growthConf);
            fighter.setHealthBeforeFight(army.health/100);
    	}

    	fighter.addAttackBeforeFight(attackRate);
    	fighter.addDefenceBeforeFight(defenceRate);
    	fighter.addMdefenceBeforeFight(mdefenceRate);
    	return fighter;
    },

    _processArmyFightResult: function(fieldId, camp, army, fighter, recordInfo, isWin) {
    	if (army.uid) {
            //保存玩家部队信息
    	    var player = gPlayers.get(army.uid);
            if (player) {
                var remainInfo = fighter.getRemainInfoAfterFight();
                var initHealth = 0;
                var remainHealth = 0;
                var champsbattle = player.getChampsBattle();
		        var attrs = champsbattle.attrs;
                var team = champsbattle.teams[army.id];
                if (team) {
                    objectForEach(team.team, function(pos, rid) {
		            	var roleAttr = attrs[rid];
		            	if (roleAttr) {
                            var remainAttr = remainInfo[rid];
                            if (remainAttr) {
                                roleAttr.health = remainAttr.health;
                            }
                            initHealth += roleAttr.init_health;
                            remainHealth += roleAttr.health;
                        }
                    });
		            player.markDirty('champsbattle.attrs');
                    army.health = Math.floor(remainHealth / Math.max(1, initHealth) * ARMY_HEALTH_BASE);
                } else {
                    army.health = 0;
                    ERROR(util.format('champsbattle uid=%d teamId=%d invalid', army.uid, army.id));
                }
            } else {
                army.health = 0;
                ERROR(util.format('champsbattle uid=%d invalid', army.uid));
            }
        } else {
            var initHealth = fighter.getTeamInitHealth();
            var remainHealth = fighter.getTeamRemainHealth();
            army.health = Math.floor(remainHealth / Math.max(1, initHealth) * ARMY_HEALTH_BASE);
        }

        army.dead = (army.health < 1) ? true : false;
        army.kill = isWin ? (army.kill + 1) : 0;
        army.status = {
            action: Action.kBattle, 
            start: this.nowTime, 
            timeout: gConfGlobal.ChampsBattleBattleNeedTime, 
            param: army.dead || !isWin,
        };

        var score = isWin ? Math.min(200, army.kill*20 + 80) : 60;
        if (army.uid) {
            army.score += score;
        } else {
            //保存npc获得的积分
            var fieldHistory = this.data.fieldHistorys[fieldId];
            for (var sid in fieldHistory) {
                var serverHistory = fieldHistory[sid];
                if (camp == serverHistory.camp) {
                    serverHistory.npcScore += score;
                }
            }
            this.markDirty('fields');
        }
        
        recordInfo.name = army.name;
        recordInfo.uid = army.uid;
        recordInfo.id = army.id;
        recordInfo.score = score;
        recordInfo.sid = this.getSidFromFieldCamp(fieldId, camp);
    },

    _saveArmyFightRecord: function(army, record) {
    	if (!army.uid) {
            return;
        }

        var userCache = this.cacheUsers[army.uid];
        if (userCache) {
            userCache.records.add(record);
        }
    },
   

    //更新战场
    _doUpdateFields: function() {
  		var fields = this.data.fields;
        var fieldHistorys = this.data.fieldHistorys;
    	for (var fieldId in fields) {
    		var field = fields[fieldId];
    		for (var cityId in field) {
    			var city = field[cityId];
    			var cityConf = gConfChampsBattleFieldCity[cityId];

                if (City.kMain == cityConf.Type) {
					this._doUpdateFieldCityRecover(fieldId, city, cityConf);
                } else {
                    if (cityConf.ResourcePerHour) {
                        this._doUpdateFieldCityResource(fieldId, city, cityConf);
                    }
                    if (cityConf.ScorePerHour) {
                        this._doUpdateFieldCityScore(fieldId, city, cityConf);
                    }
                }
    		}
    	}
        this.markDirty('fields');
    },
    
    //更新战场城池，回复部队血量
    _doUpdateFieldCityRecover: function(fieldId, city, cityConf) {
    	var camp = city.camp;
    	var armys = city.armys[camp];
    	
    	var recoverRate = gConfGlobal.ChampsBattleMainRecoverVelocity/100;
        var recoverHealth = gConfGlobal.ChampsBattleMainRecoverVelocity*100;
        objectForEach(armys, function(sn, army) {
    		if (!army.uid || army.dead || army.status || army.health >= ARMY_HEALTH_BASE) {
    			return;
    		}

            army.health = Math.min(ARMY_HEALTH_BASE, army.health + recoverHealth);
            var player = gPlayers.get(army.uid);
            if (player) {
                player.recoverChampsBattleTeam(army.id, recoverRate);
            }
    	});
    },
    
    //更新战场城池，采集资源
    _doUpdateFieldCityResource: function(fieldId, city, cityConf) {
   		var camp = city.camp;
    	var armys = city.armys[camp];
    	var addResource = cityConf.ResourcePerHour/60/gConfGlobal.ChampsBattleTeamRoleCount;
    	
        objectForEach(armys, function(sn, army) {
    		if (!army.uid) {
    			return;
    		}
    		
	    	var player = gPlayers.get(army.uid);
	    	if (!player) {
	    		return;
	    	}
	    	
	    	var gradeLevel = player.user.status.gradeLevel || 1;
	    	var gradeValueConf = gConfGradeLevel[gradeLevel];
	    	if (!gradeValueConf) {
	    		return;
	    	}

            var team = player.getChampsBattle().teams[army.id];
            if (!team || !team.team) {
                return;
            }

            var teamRoleNum = Object.keys(team.team).length || 1;
            var maxResource = gradeValueConf.ChampsBattleResource;
            army.resource = Math.min(army.resource + Math.floor(addResource*teamRoleNum), maxResource);
    	});
    },
   
    //更新战场城池，获得积分
    _doUpdateFieldCityScore: function(fieldId, city, cityConf) {
        objectForEach(city.armys, function(camp, armys) {	
            var scoreFactor = (camp == city.camp) ? gConfChampsBattleCityLevel[city.level].ScoreFactor : 1;
            var addScore = Math.floor(cityConf.ScorePerHour/60*scoreFactor);
            objectForEach(armys, function(sn, army) {
                if (army.uid) {
                    army.score += addScore;
                }
            });
    	});
    },

    //更新战场排行榜
    _doUpdateFieldRanks: function() {
    	var cacheUsers = this.cacheUsers;
        var servers = this.data.servers;

    	//统计各战场各玩家的积分
        var allFieldRanks = {}; //{$fieldId:{users:[{uid,score,sid}], servers:{$sid:score}}}
        objectForEach(cacheUsers, function(uid, userCache) {
            var score = 0;
            objectForEach(userCache.teams, function(id, team) {
                score += team.army.score;
            });

            if (score > 0) {
                var sid = userCache.sid;
                var server = servers[sid];
                if (server) {
                    var fieldId = server.fieldId;
                    var fieldRanks = allFieldRanks[fieldId];
                    if (!fieldRanks) {
                        fieldRanks = {users:[], servers:{}};
                        allFieldRanks[fieldId] = fieldRanks;
                    }

                    fieldRanks.users.push({uid:uid, score:score, sid:sid});
                    addAttrValue(fieldRanks.servers, sid, score);
                }
            }
        });

        var cacheFields = this.cacheFields;
        var fieldHistorys = this.data.fieldHistorys;
        objectForEach(allFieldRanks, function(fieldId, fieldRanks) {
            //更新各战场的玩家排行榜
            var fieldTopUsers = {};
            var fieldUsers = fieldRanks.users;
            fieldUsers.sort(function(a, b) {return b.score - a.score;});
            for (var i = 0, len = Math.min(fieldUsers.length, 10); i < len; ++i) {
                var rankUser = fieldUsers[i];
                var player = gPlayers.get(rankUser.uid);
                if (player) {
                    fieldTopUsers[rankUser.uid] = {sid:rankUser.sid, name:player.user.info.un, score:rankUser.score, rank:i+1};
                }
            }
            cacheFields[fieldId].topUsers = fieldTopUsers;

            //更新各区服的总积分
            var fieldServers = fieldRanks.servers;
            var fieldHistory = fieldHistorys[fieldId];
            for (var sid in fieldServers) {
                var serverHistory = fieldHistory[sid];
                if (serverHistory) {
                    serverHistory.score = serverHistory.npcScore + fieldServers[sid];
                }
            }
        });
    },


    //准备战场数据
    _prepareFields: function(fieldIdArray) {
        var fieldHistorys = this.data.fieldHistorys;
        this.data.fields = {};
        fieldIdArray.forEach(function (fieldId) {
            if (!fieldHistorys.hasOwnProperty(fieldId)) {
                return;
            }

            var field = {};
            this.data.fields[fieldId] = field;

            for (var cityId in gConfChampsBattleFieldCity) {
                var cityId = +cityId;
                var cityConf = gConfChampsBattleFieldCity[cityId];
                var city = {
                	id: cityId,
                    camp: cityConf.Camp,
                    level: 1,
                    resource: 0,
                    armys: {},
                }

                city.armys[Camp.kShu] = {};
                city.armys[Camp.kWei] = {};

                field[cityId] = city;
            }
        }.bind(this));

        this.markDirty('fields');
        this._rebuildCacheUsers();
        this._rebuildFieldCaches();
    },
    

	//获得真实轮数
    getRound: function() {
        return this.data.round;
    },

	//获取真实阶段
    getSchedule: function() {
        return this.data.schedule;
    },
    
    //是否处于战斗阶段
    isFightingSchedule: function() {
        return runtimeChampsBattle.isFightingSchedule(this.data.schedule);
    },
    
    //获得当前时间
    getNowTime: function() {
    	return this.nowTime;
    },
    
    //随机一支NPC部队,返回部队id
    randNpcTeam: function(fieldId) {
        var matchDay = this.cacheFields[fieldId].npcDay || 1;
        var indexs = runtimeChampsBattle.teamIndexs[matchDay];
        return common.randArray(indexs);
    },

    getData: function() {
        return this.data;
    },

    //服务器报名
    register: function(sid, ranks, startTime, fightForce) {
        this.data.registers[sid] = ranks;
        this.data.servers[sid] = {
            sid: sid,
            fieldId: 0,
            camp: Camp.kMid,
            fight_force: fightForce,
            worth: 0,
            startTime: startTime,
        };
        this.markDirty('registers');
        this.markDirty('servers');
        this._buildServerCacheUsers(sid);
        this.save();
    },

    //区服是否报名
    isRegistered: function(sid) {
        return this.data.registers.hasOwnProperty(sid);
    },

    //玩家是否有资格进入
    isUserEnterable: function(uid) {
        return this.cacheUsers.hasOwnProperty(uid);
    },
    
    //获取玩家缓存数据
    getUserCache: function(uid, needUpdate) {
        return this.cacheUsers[uid];
    },

    //添加玩家部队到战场城池，返回部队数量
	addPlayerToFieldCity: function(fieldId, camp, player) {
        var field = this.data.fields[fieldId];
        if (!field) {
            ERROR(util.format('champsbattle addPlayerToFieldCity failed! field=%d', field));
            return 0;
        }

        var cityId = runtimeChampsBattle.mainCitys[camp];
        var city = field[cityId];
        if (!city) {
            ERROR(util.format('champsbattle addPlayerToFieldCity failed! city=%d', cityId));
            return 0;
        }

        var uid = player.uid;
        var name = player.user.info.un;
        var armys = city.armys[camp];
        var userCache = this.cacheUsers[uid];
        var champsbattle = player.getChampsBattle();
        var teams = champsbattle.teams;
        var teamCount = 0;

        for (var id in teams) {
            if (Object.keys(teams[id].team).length < 1) {
                continue;
            }

        	var sn = this.newArmySN();
            var army = {
                uid: uid, 
                id: +id,
                kill: 0,
                health: ARMY_HEALTH_BASE,
                name: name,
                score: 0,
                resource: 0,
            };
        	armys[sn] = army;
        	userCache.teams[id] = {city:cityId, sn:sn, army:army};
            teamCount++;
        }

        this.markDirty('fields');
        return teamCount;
    },
    
    //添加部队到战场城池
    addArmyToFieldCity: function(fieldId, cityId, camp, army) {
        var field = this.data.fields[fieldId];
        if (!field) {
            return 0;
        }

        var city = field[cityId];
        if (!city) {
            return 0;
        }
    
        var newSN = this.newArmySN();
        if (army.uid) {
            var userCache = this.cacheUsers[army.uid];
            if (userCache) {
                var teamCache = userCache.teams[army.id];
                if (teamCache) {
                    teamCache.city = cityId;
                    teamCache.sn = newSN;
                }
            }
        }

        city.armys[camp][newSN] = army;
        this.markDirty('fields');

        return newSN;
    },
    
	getNowFreeReliveTimes: function() {
 		var freeReliveTimes = 0;
 		var nowStepRoundSeconds = this.stepStartRoundSeconds;
 		for (var t in gConfChampsBattleRelive) {
 			var conf = gConfChampsBattleRelive[t];
 			if (nowStepRoundSeconds < conf.TimeSeconds) {
 				break;
 			}
 			freeReliveTimes = conf.Times;
 		}
 		return freeReliveTimes;
 	},

    getServer: function(sid) {
        return this.data.servers[sid];
    },
    
    //查找服务器所在战场历史数据
    getServerFieldHistory: function(step, sid) {
        var fieldHistorys = this.data.fieldHistorys;
        var fieldArr = runtimeChampsBattle.stepFields[step];
        for (var i = 0, len = fieldArr.length; i < len; ++i) {
            var fieldId = fieldArr[i];
            var fieldHistory = fieldHistorys[fieldId];
            if (fieldHistory.hasOwnProperty(sid)) {
                return fieldHistory;
            }
        }
    },
    
    //通过战场阵营获取所属区服
    getSidFromFieldCamp: function(fieldId, camp) {
        var fieldHistory = this.data.fieldHistorys[fieldId];
        if (fieldHistory) {
            for (var sid in fieldHistory) {
                if (camp == fieldHistory[sid].camp) {
                    return sid;
                }
            }
        }
        return 0;
    }
}


exports.gmChangeArmy = function(player, req, resp, onHandled) {
    var uid = player.uid;
    var teamId = +req.args.id;
    var keyName = req.args.name;
    var keyValue = +req.args.value;

    do {
        if (!gChampsBattle.isFightingSchedule()) {
            resp.code = 1; resp.desc = "not fighting"; break;
        }
        
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

		var teamCache = userCache.teams[teamId];
		if (!teamCache) {
            resp.code = 1; resp.desc = "not in field"; break;
		}

        teamCache.army[keyName] = keyValue;
    } while (false);

    onHandled();
}

exports.get = function(player, req, resp, onHandled) {
    resp.nolog = 1;
    var sid = req.sid;
    var uid = player.uid;

    do {
        var data = gChampsBattle.getData();
        resp.data.servers = data.servers;
        resp.data.fieldHistorys = data.fieldHistorys;

        var registered = gChampsBattle.isRegistered(sid);
        resp.data.registered = registered;
        if (!registered) {
            break;
        }
        
        var enterable = gChampsBattle.isUserEnterable(uid);
        resp.data.enterable = enterable;
        resp.data.topUsers = data.serverTopUsers[sid] || {};
        resp.data.cloud_champsbattle = player.getChampsBattle();
        resp.data.roles = enterable ? (player.user.role || {}) : {};
    } while (false);
    
    onHandled();
}

exports.register = function(player, req, resp, onHandled) {
    do {
        var sid = +req.sid;
        var ranks = req.args.ranks;
        var serverStartTime = +req.args.serverStartTime;
        var fightForce = +req.args.fightForce;

        var schedule = gChampsBattle.getSchedule();
        if (schedule.step != runtimeChampsBattle.StepRegister || !schedule.keep) {
            resp.code = 1; resp.desc = 'not register time'; break; 
        }

        if (!gChampsBattle.isRegistered()) {
            gChampsBattle.register(sid, ranks, serverStartTime, fightForce);
        }
    } while (false);

    onHandled();
}

exports.saveTeams = function(player, req, resp, onHandled) {
    resp.nolog = 1;
    do {
        var uid = player.uid;
        var sid = +req.sid;
        var teams = req.args.teams;
        var userData = req.args.userData;

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }

        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

        if (Object.keys(userCache.teams).length > 0) {
            resp.code = 1; resp.desc = 'in field'; break;
        }

        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }
        
        if (!player.saveChampsBattleTeams(teams, userData)) {
            resp.code = 1; resp.desc = "team saved"; break;
        }

        gChampsBattle.addPlayerToFieldCity(server.fieldId, server.camp, player);
    } while (false);

    onHandled();
}

exports.adjustTeam = function(player, req, resp, onHandled) {
    resp.nolog = 1;
    do {
        var uid = player.uid;
        var argTeams = req.args.teams;

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }

        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

        if (Object.keys(userCache.teams).length < 1) {
            resp.code = 1; resp.desc = 'team empty'; break;
        } 

        var champsbattle = player.getChampsBattle();
        var teams = champsbattle.teams;
        var teamOK = true;
        for (var teamId in argTeams) {
            var argTeam = argTeams[teamId];
            var team = teams[teamId];
            if (!team) {
                teamOK = false; break;
            }

            var teamRoles = {}; //rid,pos
            var teamForm = team.team;
            var oldRoleNum = 0;
            for (var pos in teamForm) {
                teamRoles[teamForm[pos]] = pos;
                oldRoleNum++;
            }
            
            var nowRoleNum = 0;
            for (var pos in argTeam) {
                var rid = argTeam[pos];
                if (!teamRoles.hasOwnProperty(rid)) {
                    teamOK = false; break;
                }
                nowRoleNum++;
            }

            if (oldRoleNum != nowRoleNum) {
                teamOK = false;
            }

            if (!teamOK) {
                break;
            }
        }

        if (!teamOK) {
            resp.code = 1; resp.desc = "team wrong"; break;
        }

        for (var teamId in argTeams) {
            teams[teamId].team = argTeams[teamId];
            player.markDirty(util.format('champsbattle.teams.%d.team', teamId));
        }

        resp.data.teams = teams;
    } while (false);

    onHandled();
}

exports.getField = function(player, req, resp, onHandled) {
    resp.nolog = 1;
    var uid = player.uid;

    do {
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }
        
        var fieldId = server.fieldId;
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }

        if (Object.keys(userCache.teams).length < 1) {
            resp.code = 1; resp.desc = 'team empty'; break;
        } 

        //构造返回数据
        var fieldResp = {};
        for (var cityId in field) {
            var city = field[cityId];
            var cityResp = {level: city.level, armyNums: {},}
            for (var camp in city.armys) {
                cityResp.armyNums[camp] = Object.keys(city.armys[camp]).length;
            }
            fieldResp[cityId] = cityResp;
        }

        resp.data.cloud_champsbattle = player.getChampsBattle();
        resp.data.fieldHistory = data.fieldHistorys[fieldId];
        resp.data.field = fieldResp;
        resp.data.teaminfos = userCache.teams;

        var fieldCache = gChampsBattle.cacheFields[fieldId];
        resp.data.messages = fieldCache.messages.items;
        resp.data.topUsers = fieldCache.topUsers;
    } while (false);

    onHandled();
}

exports.getFieldCity = function(player, req, resp, onHandled) {
    resp.nolog = 1;
	var uid = player.uid;
    var sid = req.sid;
    var cityId = +req.args.cityId;

    do {
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }
        
        if (Object.keys(userCache.teams).length < 1) {
        	resp.code = 1; resp.desc = 'no team in field'; break;
        }

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }
        
        var fieldId = server.fieldId;
        var champsbattle = player.getChampsBattle();
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }

        var city = field[cityId];
        if (!city) {
            resp.code = 1; resp.desc = 'invalid city'; break;
        }
        
        resp.data.level = city.level;
        resp.data.resource = city.resource;
        resp.data.armys = city.armys;

        var fieldCache = gChampsBattle.cacheFields[fieldId];
        resp.data.records = fieldCache.citys[cityId].records.items;
    } while (false);

    onHandled();
}

exports.getRecords = function(player, req, resp, onHandled) {
    resp.nolog = 1;
	var uid = player.uid;
    var sid = req.sid;
    var cityId = +req.args.cityId;

    do {
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }
        
        if (Object.keys(userCache.teams).length < 1) {
        	resp.code = 1; resp.desc = 'no team in field'; break;
        }

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }
        
        var fieldId = server.fieldId;
        var champsbattle = player.getChampsBattle();
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }

        resp.data.records = userCache.records.items;
    } while (false);

    onHandled();
}

exports.moveTeam = function(player, req, resp, onHandled) {
	var uid = player.uid;
    var teamId = +req.args.id;
    var destCityId = +req.args.cityId;

    do {
        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

		var teamCache = userCache.teams[teamId];
		if (!teamCache) {
			resp.data.code = Code.kTeamNotInField; break;
		}
        
        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }

        var fieldId = server.fieldId;
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }
        
        var army = teamCache.army;
        if (army.status) {
        	resp.data.code = Code.kTeamLocking; break;
        }

        if (army.dead) {
        	resp.data.code = Code.kTeamDead; break;
        }

        var curCityId = teamCache.city;
        if (curCityId == destCityId) {
            resp.code = 1; resp.desc = 'same city'; break;
        }

        var curCityConf = gConfChampsBattleFieldCity[curCityId];
        var destCityConf = gConfChampsBattleFieldCity[destCityId];
        if (!destCityConf || (curCityConf.ArrayEdge.indexOf(destCityId) < 0)) {
            resp.code = 1; resp.desc = 'invalid city'; break;
        }

        if (gChampsBattle.nowRoundSeconds < (gChampsBattle.stepStartRoundSeconds + destCityConf.OpenSeconds - 1)) {
        	resp.code = 1; resp.desc = 'city not open'; break;
        }

        //以下情况无法移动：
        //1、目标城池部队已满
        //2、目标城池是敌方的非战斗城池
        //3、目标城池是敌方城池且当前城池有敌方部队
        var camp = server.camp;
        var curCity = field[curCityId];
        var destCity = field[destCityId];
        var curCityArmys = curCity.armys[camp];
        var destCityArmys = destCity.armys[camp];
        var destCityArmyCount = Object.keys(destCityArmys).length;
        if (destCityArmyCount >= destCityConf.ArmyCapacity) {
        	resp.data.code = Code.kCityArmyFull; break;
        }
        
        if (destCity.camp != camp) {
	        if (destCityConf.Type != City.kBattle) {
	        	resp.code = 1; resp.desc = 'not battle city'; break;
	        }
	        
	        //if ((destCityArmyCount < 1) && (destCityConf.Type != City.kMid)) {
	        //	var enemyCamp = runtimeChampsBattle.getEnemyCamp(camp);
	        //	if (Object.keys(curCity.armys[enemyCamp]).length > 0) {
	        //		resp.data.code = Code.kCityExistEnemy; break;	
	        //	}
	        //}
        }
               
        //修改部队状态
        army.status = {
            action: Action.kMove, 
            start: gChampsBattle.nowTime, 
            timeout: gConfGlobal.ChampsBattleMoveNeedTime,
            param: destCityId,
        };
        gChampsBattle.markDirty('fields');
        
        resp.data.teamInfo = teamCache;
    } while (false);

    onHandled();
}

exports.reliveTeam = function(player, req, resp, onHandled) {
	var uid = player.uid;
	var teamId = +req.args.id;
	var isCash = +req.args.cash;
	var ownCash = +req.args.ownCash;
	
	do {
        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

		var teamCache = userCache.teams[teamId];
		if (!teamCache) {
			resp.data.code = Code.kTeamNotInField; break;
		}
        

        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }
        
        var curCityId = teamCache.city;
        if (curCityId != runtimeChampsBattle.mainCitys[server.camp]) {
        	resp.code = 1; resp.desc = "not in main city"; break;
        }
        
        //复活部队
        var cost = 0;
        var champsbattle = player.getChampsBattle();
        var team = champsbattle.teams[teamId];
        if (isCash) {
            var confBuy = gConfBuy[team.cashRelive + 1];
            if (!confBuy || !confBuy.CashChampsBattle) {
        		resp.data.code = Code.kNoReliveTimes; break;
            }
            
            cost = confBuy.CashChampsBattle;
        	if (cost > ownCash) {
        		resp.code = 1; resp.desc = "cash not enough"; break;
        	}  
        	
        	team.cashRelive++;
        	player.markDirty(util.format('champsbattle.teams.%d.cashRelive', teamId));
        } else {
        	if (team.freeRelive >= gChampsBattle.getNowFreeReliveTimes()) {
        		resp.data.code = Code.kNoReliveTimes; break;
        	}
        	
        	team.freeRelive++;
        	player.markDirty(util.format('champsbattle.teams.%d.freeRelive', teamId));
        }
        
        //恢复部队血量
        var attrs = champsbattle.attrs;
        objectForEach(team.team, function(pos, rid) {
        	var attr = attrs[rid];
        	attr.health = attr.init_health;
        });
        player.markDirty('champsbattle.attrs');

        teamCache.army.dead = false;
        teamCache.army.health = ARMY_HEALTH_BASE;
        gChampsBattle.markDirty('fields');
        
        resp.data.cash = -cost;
        resp.data.attrs = attrs;
        resp.data.army = teamCache.army;
        resp.data.cashRelive = team.cashRelive;
        resp.data.freeRelive = team.freeRelive;
	} while (false);
	
	onHandled();
}

exports.summon = function(player, req, resp, onHandled) {
	var uid = player.uid;
	var teamId = +req.args.id;
	
	do {
        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

		var teamCache = userCache.teams[teamId];
		if (!teamCache) {
			resp.data.code = Code.kTeamNotInField; break;
		}

        var data = gChampsBattle.getData();
        var sid = userCache.sid;
        var server = data.servers[sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }

        var fieldId = server.fieldId;
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }

        var needResource = gConfGlobal.ChampsBattleSummonResource;
        if (teamCache.army.resource < needResource) {
            resp.code = 1; resp.desc = 'resource not enough'; break;
        }
        
        var camp = server.camp;
        var destCityId = common.randArray(runtimeChampsBattle.battleCitys[camp]);
        var npcTeamId = gChampsBattle.randNpcTeam(fieldId);
        var army = {uid:0, id:npcTeamId, kill:0, health:ARMY_HEALTH_BASE};
        var armySN = gChampsBattle.addArmyToFieldCity(fieldId, destCityId, camp, army);
        teamCache.army.resource -= needResource;
        gChampsBattle.markDirty('fields');

        var message = {
            stamp: gChampsBattle.getNowTime(),
            name: player.user.info.un,
            sid: sid,
            id: npcTeamId,
            city: destCityId,
        }
        gChampsBattle.cacheFields[fieldId].messages.add(message);
        
        resp.data.army = army;
        resp.data.armySN = armySN;
        resp.data.cityId = destCityId;
        resp.data.resource = -needResource;
	} while (false);
	
	onHandled();
}

exports.contribute = function(player, req, resp, onHandled) {
	var uid = player.uid;
	var teamId = +req.args.id;
    var resource = +req.args.resource;
	
	do {
        if (resource <= 0) {
            resp.code = 1; resp.desc = 'invalid resource'; break;
        }

        if (!gChampsBattle.isFightingSchedule()) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }

        var teamCache = userCache.teams[teamId];
		if (!teamCache) {
			resp.data.code = Code.kTeamNotInField; break;
		}
        
        var data = gChampsBattle.getData();
        var server = data.servers[userCache.sid];
        if (!server || (Camp.kMid == server.camp)) {
            resp.code = 1; resp.desc = 'no field'; break;
        }

        var fieldId = server.fieldId;
        var field = data.fields[fieldId];
        if (!field) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }
        
        var army = teamCache.army;
        if (resource > army.resource) {
            resp.code = 1; resp.desc = 'resource not enough'; break;
        }
        
        var cityId = teamCache.city;
        var city = field[cityId];
        if (city.camp != server.camp) {
            resp.code = 1; resp.desc = 'city camp error'; break;
        }

        var cityConf = gConfChampsBattleFieldCity[cityId];
        if (!cityConf || cityConf.Type != City.kBattle) {
            resp.code = 1; resp.desc = 'not battle city'; break;
        }

        if (!gConfChampsBattleCityLevel[city.level + 1]) {
            resp.code = 1; resp.desc = 'top level'; break;
        }

        city.resource += resource;
        var levelConf = gConfChampsBattleCityLevel[city.level];
        while (city.resource >= levelConf.NextSource) {
            var nextLevelConf = gConfChampsBattleCityLevel[city.level + 1];
            if (nextLevelConf) {
                city.level += 1;
                city.resource -= levelConf.NextSource;
                levelConf = nextLevelConf;
            } else {
                city.resource = 0;
                break;
            }
        }
        
        army.resource -= resource;
        gChampsBattle.markDirty('fields');

        resp.data.level = city.level;
        resp.data.resource = city.resource;
	} while (false);
	
	onHandled();
}

exports.getStepAward = function(player, req, resp, onHandled) {
	var uid = player.uid;
    var step = +req.args.step;
    var support = +req.args.support;

    do {
        var schedule = gChampsBattle.getSchedule();
        if (schedule.keep || (schedule.step <= runtimeChampsBattle.StepRegister)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        var awards = [];
        var data = gChampsBattle.getData();
        var userCache = gChampsBattle.getUserCache(uid);
        if (userCache) {
            var sid = userCache.sid;
            var topUsers = data.serverTopUsers[sid];
            if (topUsers && topUsers.hasOwnProperty(uid)) {
                resp.data.topAward = true;
            }
            
            var score = player.getChampsBattle().score;
            resp.data.glory = score;
        }

        if (support) {
            var fieldHistory = gChampsBattle.getServerFieldHistory(step, support);
            if (fieldHistory && fieldHistory[support].win) {
                resp.data.supportAward = true;
            }
        }
    } while (false);

	onHandled();
}

exports.getFinalAward = function(player, req, resp, onHandled) {
	var uid = player.uid;

    do {
        var userCache = gChampsBattle.getUserCache(uid);
        if (!userCache) {
            resp.code = 1; resp.desc = 'not enterable'; break;
        }
        
        var sid = userCache.sid;
        var data = gChampsBattle.getData();
        var server = data.servers[sid];
        if (!server || !server.fieldId) {
            resp.code = 1; resp.desc = 'no fight'; break;
        }

        var serverHistory = data.fieldHistorys[server.fieldId][sid];
        resp.data.fieldId = server.fieldId;
        resp.data.win = (serverHistory && serverHistory.win) ? 1 : 0;
    } while (false);

	onHandled();
}

exports.support = function(player, req, resp, onHandled) {
    do {
        var sid = +req.args.sid;
        var step = +req.args.step;

        var server = gChampsBattle.getServer(sid);
        if (!server) {
            resp.code = 1; resp.desc = 'invalid server'; break;
        }

        var fieldHistory = gChampsBattle.getServerFieldHistory(step, sid);
        if (!fieldHistory) {
            resp.code = 1; resp.desc = 'invalid field'; break;
        }

        if (Object.keys(fieldHistory).length < 2) {
            resp.code = 1; resp.desc = 'field not full'; break;
        }

        var stepConf = gConfChampsBattleSchedule[step];
        var levelConf = gConfLevel[player.user.status.level];
        server.worth += Math.floor(levelConf.ChampsBattleSupport * stepConf.SupportGold);
        gChampsBattle.markDirty('servers');
    } while (false);

	onHandled();
}

exports.getReplay = function(player, req, resp, onHandled) {
    resp.nolog = 1;
    do {
        gReplay.getReplay(+req.args.id, function(battle){
            if( battle ) {
                resp.data.battle = battle;
            }
	        onHandled();
        });
        return;
    } while (false);

	onHandled();
}

exports.ChampsBattle = ChampsBattle;
